// 该文件与tx_p2联合实现点对点聊天 使用io多路复用的方式

#include <sys/time.h>
#include <stdio.h>
#include <unistd.h>
#include <error.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>

#define MAXLINE 1024
// select返回就绪的io事件的个数，超时则返回0 失败返回-1 并设置errno

int main(int argc, char *argv[])
{
    // 先在外面创建有名管道 FIFO
    // 一切皆文件
    // 打开管道 open的返回值为文件描述符
    int fd1 = open("p1", O_WRONLY);
    if (fd1 == -1)
    {
        // 返回-1 打开文件失败
        error(1, errno, "open f1 fail");
    }
    int fd2 = open("p2", O_RDONLY);
    if (fd2 == -1)
    {
        error(1, errno, "open f2 fail");
    }

    // 1.设置感兴趣的文件描述符也就是要监听的文件描述符
    fd_set mainfds;
    // 先清空fdset所指向的集合
    FD_ZERO(&mainfds);

    // 将文件描述符fd添加到fdset指向的集合中
    FD_SET(STDIN_FILENO, &mainfds);
    int maxfd = STDIN_FILENO;
    // p1 检测 管道p2

    printf("开始聊天：\n");
    FD_SET(fd2, &mainfds);
    if (fd2 > maxfd)
    {
        maxfd = fd2;
    }

    // 定义数组，用来存储输出输入信息
    char sndline[MAXLINE];
    char recline[MAXLINE];

    while (1)
    {
        // 因为select 参数为传入传出参数，会改变参数的值，所以复制一份每一次都是监测值
        // 这也是fd_set 设计的妙处 结构体的赋值就是结构体的复制，这是不使用数组的原因
        fd_set readfd = mainfds;
        // 因为这是用来处理阻塞点的所以，只要监听read就可以了
        int nfd = select(maxfd + 1, &readfd, NULL, NULL, NULL);
        switch (nfd)
        {
        case -1:
            error(1, errno, "select");
        case 0:
            // 超时
            printf("time out\n");
            continue;
        default:
            // STDIN就绪
            if (FD_ISSET(STDIN_FILENO, &readfd))
            {
                fgets(sndline, MAXLINE, stdin);
                write(fd1, sndline, strlen(sndline) + 1);
            }
            // fd2就绪
            if (FD_ISSET(fd2, &readfd))
            {
                int num = read(fd2, recline, MAXLINE);
                // 处理Ctrl+d的情况就是流末尾,读取到数据才打印
                if (num == 0)
                {
                    // 没有读取到数据，说明对面的通道关闭
                    goto end;
                }
                else if (num == -1)
                {
                    error(1, errno, "read");
                }
                printf("for 2 : %s", recline);
            }
        }
    }

end:
    close(fd1);
    close(fd2);
    return 0;
}